/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.cef.core.datatype;

import com.inspur.edp.cef.api.dataType.valueObj.ICefValueObjContext;
import com.inspur.edp.cef.api.determination.ICefDeterminationContext;
import com.inspur.edp.cef.core.determination.ValueObjDeterminationExecutor;
import com.inspur.edp.cef.core.determination.builtinimpls.CefAfterModifyDtmAssembler;
import com.inspur.edp.cef.core.determination.builtinimpls.CefB4SaveDtmAssembler;
import com.inspur.edp.cef.core.determination.builtinimpls.CefRetrieveDefaultDtmAssembler;
import com.inspur.edp.cef.core.determination.builtinimpls.ValueObjAfterModifyDtmAssembler;
import com.inspur.edp.cef.core.determination.builtinimpls.ValueObjBeforeSaveDtmAssembler;
import com.inspur.edp.cef.core.determination.builtinimpls.ValueObjRetriveDefaultDtmAssembler;
import com.inspur.edp.cef.core.determination.fieldrtrimdtmadaptor.FieldRtrimDtmUtils;
import com.inspur.edp.cef.core.validation.builtinimpls.CefAfterModifyValAssembler;
import com.inspur.edp.cef.core.validation.builtinimpls.CefB4SaveValAssembler;
import com.inspur.edp.cef.core.validation.builtinimpls.ValueObjAfterModifyValAssembler;
import com.inspur.edp.cef.core.validation.builtinimpls.ValueObjBeforeSaveValAssembler;
import com.inspur.edp.cef.core.validation.lengthvaladaptor.LengthValUtils;
import com.inspur.edp.cef.core.validation.requiredvaladaptor.RequiredValsUtils;
import com.inspur.edp.cef.core.validation.requiredvaladaptor.ValueObjValidationExecutor;
import com.inspur.edp.cef.entity.changeset.IChangeDetail;
import com.inspur.edp.cef.entity.changeset.ValueObjModifyChangeDetail;
import com.inspur.edp.cef.spi.determination.IDetermination;
import com.inspur.edp.cef.spi.determination.IValueObjRTDtmAssembler;
import com.inspur.edp.cef.spi.determination.basetypes.nestedTrans.CefNestedTransAfterModifyDtmAdapter;
import com.inspur.edp.cef.spi.determination.basetypes.nestedTrans.CefNestedTransB4SaveDtmAdapter;
import com.inspur.edp.cef.spi.determination.basetypes.nestedTrans.CefNestedTransRetrieveDefaultDtmAdapter;
import com.inspur.edp.cef.spi.entity.AssociationInfo;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.AssocationPropertyInfo;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.DataTypePropertyInfo;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.ObjectType;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.UdtPropertyInfo;
import com.inspur.edp.cef.spi.entity.resourceInfo.ValueObjResInfo;
import com.inspur.edp.cef.spi.entity.resourceInfo.builinImpls.CefEntityResInfoImpl;
import com.inspur.edp.cef.spi.entity.resourceInfo.builinImpls.CefValueObjResInfo;
import com.inspur.edp.cef.spi.validation.IValidation;
import com.inspur.edp.cef.spi.validation.IValueObjRTValidationAssembler;
import com.inspur.edp.cef.spi.validation.basetypes.nestedtrans.CefNestedTransAftModifyValAdapter;
import com.inspur.edp.cef.spi.validation.basetypes.nestedtrans.CefNestedTransB4SaveValAdapter;
import lombok.SneakyThrows;

import java.util.Map;

public abstract class CefValueObject extends CefDataType
{
	public ICefValueObjContext getValueObjContext() {
		return (ICefValueObjContext)super.getContext();
	}

	public void setValueObjContext(ICefValueObjContext value) {
		super.setContext(value);
	}
	public final void retrieveDefaultDeterminate() {
		IValueObjRTDtmAssembler ass = getRetrieveDefaultDtmAssembler();
		if (ass == null) {
			return;
		}

		new ValueObjDeterminationExecutor(getValueObjContext(), ass, null).execute();
	}

	public void retrieveDefaultDeterminate(ICefDeterminationContext parent) {
		retrieveDefaultDeterminate();
	}

	protected IValueObjRTDtmAssembler getRetrieveDefaultDtmAssembler()
	{
		if(getVersion()==0)
		return createRetrieveDefaultDtmAssembler();
		if(getValueObjCacheInfo().getRetrieveDefaultDtmsAssembler()!=null)
			return getValueObjCacheInfo().getRetrieveDefaultDtmsAssembler();
		ValueObjRetriveDefaultDtmAssembler retrieveDefaultDtmAssembler = (ValueObjRetriveDefaultDtmAssembler) createRetrieveDefaultDtmAssembler();
		addRetrieveDefaultDtm(retrieveDefaultDtmAssembler);
		addBuiltInRetrieveDefaultDtms(retrieveDefaultDtmAssembler);
		getValueObjCacheInfo().setRetrieveDefaultDtmsAssembler(retrieveDefaultDtmAssembler);
		return retrieveDefaultDtmAssembler;
	}

	protected void addRetrieveDefaultDtm(ValueObjRetriveDefaultDtmAssembler assembler) {
	}

	private void addBuiltInRetrieveDefaultDtms(
			ValueObjRetriveDefaultDtmAssembler retrieveDefaultDtmAssembler) {
		int index =0;
		for(Map.Entry entry:getValueObjResInfo().getEntityTypeInfo().getPropertyInfos().entrySet())
		{
			if(entry.getValue() instanceof UdtPropertyInfo==false)
				continue;
			DataTypePropertyInfo udtPropertyInfo= (DataTypePropertyInfo) entry.getValue();
			retrieveDefaultDtmAssembler.insertBelongingDetermination(createRetrieveDefaultUdtTransDtm(udtPropertyInfo),index++);
		}
	}

	private IDetermination createRetrieveDefaultUdtTransDtm(DataTypePropertyInfo udtPropertyInfo) {
		CefNestedTransRetrieveDefaultDtmAdapter adapter=
				new CefNestedTransRetrieveDefaultDtmAdapter(udtPropertyInfo.getPropertyName(),udtPropertyInfo.getPropertyName(),((UdtPropertyInfo)udtPropertyInfo.getObjectInfo()).getUdtConfigId());
		return adapter;
	}

	protected IValueObjRTDtmAssembler createRetrieveDefaultDtmAssembler(){return null;}

	public final void afterModifyDeterminate(ValueObjModifyChangeDetail change) {
		IValueObjRTDtmAssembler ass = getAfterModifyDtmAssembler();
		if (ass == null) {
			return;
		}

		new ValueObjDeterminationExecutor(getValueObjContext(), ass, change).execute();
	}

	public void afterModifyDeterminate(ICefDeterminationContext parent, ValueObjModifyChangeDetail change) {
		afterModifyDeterminate(change);
	}

	protected final IValueObjRTDtmAssembler getAfterModifyDtmAssembler() {
		if(getVersion()==0)
			return createAfterModifyDtmAssembler();
		if(getValueObjCacheInfo().getAfterModifyDtmsAssembler()!=null)
			return getValueObjCacheInfo().getAfterModifyDtmsAssembler();
		ValueObjAfterModifyDtmAssembler afterModifyDtmAssembler = (ValueObjAfterModifyDtmAssembler) createAfterModifyDtmAssembler();
		addAfterModifyDtm(afterModifyDtmAssembler);
		addBuiltInAfterModifyDtms(afterModifyDtmAssembler);
		getValueObjCacheInfo().setAfterModifyDtmsAssembler(afterModifyDtmAssembler);
		return afterModifyDtmAssembler;
	}

	protected void addAfterModifyDtm(ValueObjAfterModifyDtmAssembler assembler) {
	}

	private void addBuiltInAfterModifyDtms(ValueObjAfterModifyDtmAssembler afterModifyDtmAssembler) {
		FieldRtrimDtmUtils.addFieldRtrimDtm(afterModifyDtmAssembler,getValueObjResInfo().getEntityTypeInfo());
		int index =0;
		for(Map.Entry entry:getValueObjResInfo().getEntityTypeInfo().getPropertyInfos().entrySet())
		{
			if(entry.getValue() instanceof UdtPropertyInfo==false)
				continue;
			DataTypePropertyInfo udtPropertyInfo= (DataTypePropertyInfo) entry.getValue();
			afterModifyDtmAssembler.insertBelongingDetermination(createAfterModifyUdtTransDtm(udtPropertyInfo),index++);
		}
	}

	private IDetermination createAfterModifyUdtTransDtm(DataTypePropertyInfo udtPropertyInfo) {
		CefNestedTransAfterModifyDtmAdapter adapter=
				new CefNestedTransAfterModifyDtmAdapter(udtPropertyInfo.getPropertyName(),udtPropertyInfo.getPropertyName(),((UdtPropertyInfo)udtPropertyInfo.getObjectInfo()).getUdtConfigId());
		return adapter;
	}

	protected IValueObjRTDtmAssembler createAfterModifyDtmAssembler(){return null;}

	public final void beforeSaveDeterminate(ValueObjModifyChangeDetail change) {
		IValueObjRTDtmAssembler ass = getBeforeSaveDtmAssembler();
		if (ass == null) {
			return;
		}

		new ValueObjDeterminationExecutor(getValueObjContext(), ass, change).execute();
	}

	public void beforeSaveDeterminate(ICefDeterminationContext parent, ValueObjModifyChangeDetail change) {
		beforeSaveDeterminate(change);
	}

	protected final IValueObjRTDtmAssembler getBeforeSaveDtmAssembler() {
		if(getVersion()==0)
			return createBeforeSaveDtmAssembler();
		if(getValueObjCacheInfo().getBeforeSaveDtmAssembler()!=null)
			return getValueObjCacheInfo().getBeforeSaveDtmAssembler();
		ValueObjBeforeSaveDtmAssembler b4SaveDtmAssembler = (ValueObjBeforeSaveDtmAssembler) createBeforeSaveDtmAssembler();
		addBeforeSaveDtm(b4SaveDtmAssembler);
		addBuiltInB4SaveDtms(b4SaveDtmAssembler);
		getValueObjCacheInfo().setBeforeSaveDtmAssembler(b4SaveDtmAssembler);
		return b4SaveDtmAssembler;
	}

	protected void addBeforeSaveDtm(ValueObjBeforeSaveDtmAssembler assembler){
	}

	private void addBuiltInB4SaveDtms(ValueObjBeforeSaveDtmAssembler b4SaveDtmAssembler) {
		int index =0;
		for(Map.Entry entry:getValueObjResInfo().getEntityTypeInfo().getPropertyInfos().entrySet())
		{
			if(entry.getValue() instanceof UdtPropertyInfo ==false)
				continue;
			DataTypePropertyInfo udtPropertyInfo= (DataTypePropertyInfo) entry.getValue();
			b4SaveDtmAssembler.insertBelongingDetermination(createB4SaveUdtTransDtm(udtPropertyInfo),index++);
		}
	}

	private IDetermination createB4SaveUdtTransDtm(DataTypePropertyInfo udtPropertyInfo) {
		return new CefNestedTransB4SaveDtmAdapter(udtPropertyInfo.getPropertyName(),udtPropertyInfo.getPropertyName(),((UdtPropertyInfo)udtPropertyInfo.getObjectInfo()).getUdtConfigId());
	}

	protected IValueObjRTDtmAssembler createBeforeSaveDtmAssembler() {return null;}

	public final void afterModifyValidate(ValueObjModifyChangeDetail change)
	{
		IValueObjRTValidationAssembler ass = greateAfterModifyValidationAssembler();
		if (ass == null)
		{
			return;
		}

		new ValueObjValidationExecutor(getValueObjContext(), ass, change).execute();
	}

	private IValueObjRTValidationAssembler greateAfterModifyValidationAssembler() {
		if(getVersion()==0)
			return createAfterModifyValidationAssembler();
		if(getValueObjCacheInfo().getAfterModifyValsAssembler()!=null)
			return getValueObjCacheInfo().getAfterModifyValsAssembler();
		ValueObjAfterModifyValAssembler afterModifyValAssembler = (ValueObjAfterModifyValAssembler) createAfterModifyValidationAssembler();
		addAfterModifyVal(afterModifyValAssembler);
		addBuiltInAfterModifyVals(afterModifyValAssembler);
		getValueObjCacheInfo().setAfterModifyValsAssembler(afterModifyValAssembler);
		return afterModifyValAssembler;
	}

  protected void addAfterModifyVal(ValueObjAfterModifyValAssembler assembler) {
	}

	private void addBuiltInAfterModifyVals(ValueObjAfterModifyValAssembler afterModifyValAssembler) {
		int index =0;
		for(Map.Entry entry:getValueObjResInfo().getEntityTypeInfo().getPropertyInfos().entrySet())
		{
			if(entry.getValue() instanceof UdtPropertyInfo==false)
				continue;
			DataTypePropertyInfo udtPropertyInfo= (DataTypePropertyInfo) entry.getValue();
			afterModifyValAssembler.insertBelongingVals(createAfterModifyUdtTransVal(udtPropertyInfo),index++);
		}
		LengthValUtils.addLengthVals(afterModifyValAssembler,getValueObjResInfo().getEntityTypeInfo(),getVersion());
	}

	protected  IValidation createAfterModifyUdtTransVal(DataTypePropertyInfo udtPropertyInfo) {
		return new CefNestedTransAftModifyValAdapter(udtPropertyInfo.getPropertyName(),
				udtPropertyInfo.getPropertyName(),
				((UdtPropertyInfo) udtPropertyInfo.getObjectInfo()).getUdtConfigId());
	}

	protected IValueObjRTValidationAssembler createAfterModifyValidationAssembler() {return null;}

	public final void beforeSaveValidate(ValueObjModifyChangeDetail change)
	{
		IValueObjRTValidationAssembler ass = greateBeforeSaveValidationAssembler();
		if (ass == null)
		{
			return;
		}

		new ValueObjValidationExecutor(getValueObjContext(), ass, change).execute();
	}

	private IValueObjRTValidationAssembler greateBeforeSaveValidationAssembler() {
		if(getVersion()==0)
			return createBeforeSaveValidationAssembler();
		if(getValueObjCacheInfo().getBeforeSaveValsAssembler()!=null)
			return getValueObjCacheInfo().getBeforeSaveValsAssembler();
		ValueObjBeforeSaveValAssembler b4SaveValAssembler = (ValueObjBeforeSaveValAssembler) createBeforeSaveValidationAssembler();
		addBeforeSaveVal(b4SaveValAssembler);
		addBuiltInB4SaveVals(b4SaveValAssembler);
		getValueObjCacheInfo().setBeforeSaveValsAssembler(b4SaveValAssembler);
		return b4SaveValAssembler;
	}

	protected void addBeforeSaveVal(ValueObjBeforeSaveValAssembler assembler){
	}

	private void addBuiltInB4SaveVals(ValueObjBeforeSaveValAssembler b4SaveValAssembler) {
	addUdtTransB4SaveVals(b4SaveValAssembler);
	addRequireValidations(b4SaveValAssembler);
	addUdtB4SaveVals(b4SaveValAssembler);
}

	private void addRequireValidations(ValueObjBeforeSaveValAssembler b4SaveValAssembler) {
		RequiredValsUtils.addUdtRequiredVals(b4SaveValAssembler,getValueObjResInfo().getEntityTypeInfo());

	}

	private void addUdtTransB4SaveVals(ValueObjBeforeSaveValAssembler b4SaveValAssembler) {
		int index =0;
		for(Map.Entry entry:getValueObjResInfo().getEntityTypeInfo().getPropertyInfos().entrySet())
		{
			if(entry.getValue() instanceof UdtPropertyInfo==false)
				continue;
			DataTypePropertyInfo udtPropertyInfo= (DataTypePropertyInfo) entry.getValue();
			b4SaveValAssembler.insertBelongingVals(createB4SaveUdtTransVal(udtPropertyInfo),index++);
		}
	}

	@SneakyThrows
	private void addUdtB4SaveVals(ValueObjBeforeSaveValAssembler b4SaveValAssembler){
		for(Map.Entry<String, DataTypePropertyInfo> entry:getValueObjResInfo().getEntityTypeInfo().getPropertyInfos().entrySet())
		{
			if(entry.getValue().getObjectType() == ObjectType.Association){
				if(((DataTypePropertyInfo) entry.getValue()).getObjectInfo() instanceof AssocationPropertyInfo){
					AssociationInfo associationInfo = ((AssocationPropertyInfo)((DataTypePropertyInfo) entry.getValue()).getObjectInfo()).getAssociationInfo();
					if(associationInfo==null)
						continue;
					Class c=Class.forName("com.inspur.edp.bef.builtincomponents.FKConstraints.FKCheckValidationAdaptor");
					b4SaveValAssembler.addValidations(
							(IValidation) c.getConstructor(String.class,String.class,String.class,String.class,String.class).newInstance(entry.getValue().getPropertyName(),associationInfo.getConfig(),associationInfo.getNodeCode(),associationInfo.getMainCode(),associationInfo.getPrivateSourceColumn()));
				}
			}
		}
	}

	private IValidation createB4SaveUdtTransVal(DataTypePropertyInfo udtPropertyInfo) {
		return new CefNestedTransB4SaveValAdapter(udtPropertyInfo.getPropertyName(),udtPropertyInfo.getPropertyName(),((UdtPropertyInfo)udtPropertyInfo.getObjectInfo()).getUdtConfigId(), udtPropertyInfo);
	}

	protected IValueObjRTValidationAssembler createBeforeSaveValidationAssembler() {return null;}

	@Override
	public final void modify(IChangeDetail change)
	{
		modify((ValueObjModifyChangeDetail)change);
	}

	public abstract void modify(ValueObjModifyChangeDetail change);

	protected CefValueObjCacheInfo getValueObjCacheInfo() {
		throw new RuntimeException();
	}

	public CefValueObjResInfo getValueObjResInfo()
	{return null;}
}
